package org.wattdepot.cli.command;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.cli.processor.CommandLineInterface;
import org.wattdepot.client.MiscClientException;
import org.wattdepot.client.ResourceNotFoundException;
import org.wattdepot.resource.source.jaxb.Source;
import org.wattdepot.util.tstamp.Tstamp;

/**
 * PowerStats class returns the maximum, minimum, or average power generated (or consumed), in
 * Watts, by the source for the a given day. The statistic is obtained by sampling the source at the
 * specified minute intervals throughout the course of the day. This class extends
 * CommandLineInterface to have access to the WattDepotClient and implements WattDepotCliCommand
 * interface to ensure this class does a specific command.
 * 
 * @author Edward Meyer, Bao Huy Ung
 * 
 */
public class PowerStats extends CommandLineInterface implements WattDepotCliCommand {

  /** To avoid using duplicate string literals. */
  private String stopQuote = "\".";

  /**
   * Creates a Powerstats object to return the maximum, minimum, or average power generated (or
   * consumed), in Watts, by a specific source on a given day.
   */
  public PowerStats() {
    // Empty constructor.
  }

  /**
   * Returns the requested average/max/min, in Watts, of a sampling interval, in minutes, of data.
   * 
   * @param args is the list of arguments entered by the user.
   * @return returns the interpolated data of the requested average/max/min.
   */
  public String doCommand(List<String> args) {

    // If there are too few or too many arguments, return an error message.
    if (args.size() != 9) {
      return "Error: Incorrect number of arguments were entered. Expected 9, instead "
          + args.size() + " were entered.";
    }

    boolean generation = false;
    String inputSourceName = args.get(2);
    Source inputSource = null;
    String inputStamp = args.get(4);
    XMLGregorianCalendar timeStamp = null;
    XMLGregorianCalendar endStamp = null;
    XMLGregorianCalendar currentStamp = null;
    Integer inputMinutes = 0;
    Double statistic = 0.0;
    List<Double> powerList = new ArrayList<Double>();

    // Check and set the inputed interval time to see if it is valid.
    try {
      inputMinutes = Integer.parseInt(args.get(6));
    }
    catch (NumberFormatException e) {
      return "Sample-interval was not an integer.";
    }
    if (inputMinutes < 1) {
      return "Sampling-interval must be an integer 1 or greater.";
    }

    // Check to see if user request is for generated or consumed energy.
    if (args.get(1).equalsIgnoreCase("generated")) {
      generation = true;
    }
    else if (args.get(1).equalsIgnoreCase("consumed")) {
      generation = false;
    }
    else {
      return "Error at {generated|consumed} argument. Incorrect input: \"" + args.get(1)
          + stopQuote;
    }

    // Check if a valid source was entered.
    inputSource = isValidSource(inputSourceName);
    if (inputSource == null) {
      return "\"" + inputSourceName + "\" is not a valid source.";
    }

    // Check if the correct keywords were used in the command.
    if (!args.get(3).equalsIgnoreCase("day")) {
      return "Error: Keyword \"day\" was mistyped as \"" + args.get(3) + stopQuote;
    }
    if (!args.get(5).equalsIgnoreCase("sampling-interval")) {
      return "Error: Keyword \"sampling-interval\" was mistyped as \"" + args.get(5) + stopQuote;
    }
    if (!args.get(7).equalsIgnoreCase("statistic")) {
      return "Error: Keyword \"statistic\" was mistyped as \"" + args.get(7) + stopQuote;
    }

    // Attempt to parse the entered timestamp to see if it's a valid timestamp.
    timeStamp = isValidTimestamp(inputStamp);
    if (timeStamp == null) {
      return "Timestamp: \"" + inputStamp + "\" cannot be parsed into a timestamp.";
    }

    // Calculate the ending timestamp.
    endStamp = Tstamp.incrementDays(timeStamp, 1);

    currentStamp = timeStamp;

    // Store all items in an ArrayList from starting ending to ending time.
    try {
      while (currentStamp.compare(endStamp) < 0) {
        if (generation) {
          powerList.add(client.getPowerGenerated(inputSourceName, currentStamp));
        }
        else if (!generation) {
          powerList.add(client.getPowerConsumed(inputSourceName, currentStamp));
        }
        // Increment time counter by user input interval.
        currentStamp = Tstamp.incrementMinutes(currentStamp, inputMinutes);
      }
    }
    catch (ResourceNotFoundException r) {
      return "No sensor data found for \"" + inputSourceName + "\" on timestamp: " + "\""
          + timeStamp.toString() + "\"";
    }
    catch (MiscClientException mce) {
      return "Network communication failure when retrieving sensor data.";
    }
    // If any unknown error occurred.
    catch (Exception e) {
      return "An error occured when retrieving sensor data.\n" + e;
    }

    if (args.get(8).equalsIgnoreCase("max")) {
      statistic = Collections.max(powerList);
    }
    else if (args.get(8).equalsIgnoreCase("min")) {
      statistic = Collections.min(powerList);
    }
    else if (args.get(8).equalsIgnoreCase("average")) {
      double avgStat = 0.0;
      for (double power : powerList) {
        avgStat += power;
      }
      statistic = avgStat / powerList.size();
    }
    else {
      return "Error in statisic argument. Expected {min|max|average} instead \"" + args.get(8)
          + "\" was entered.";
    }

    return statistic.toString();

  }

}
